#include <bits/stdc++.h>
#define lson i<<1
#define rson i<<1|1
const int  INF=0x7fffffff;
const int N=30005;
const int M=60005;
using namespace std;
int n,q,cnt,sz;
int v[N],dep[N],siz[N],head[N],fa[N],son[N],rk[N];
int id[N],top[N];
char ch[10];
struct Edge{
    int v,next;
}edge[M];
struct Node{
    int l,r,mx,sum,tag;
}tree[N<<2];
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addEdge(int u,int v){
    edge[cnt]=Edge{v,head[u]};
    head[u]=cnt++;
    edge[cnt]=Edge{u,head[v]};
    head[v]=cnt++;
}
void dfs1(int u,int f,int d){
    siz[u]=1;
    fa[u]=f;
    dep[u]=d;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==f){
            continue;
        }
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        //找到重儿子(size最大的子树)
        if(siz[v]>siz[son[u]]){
            son[u]=v;
        }
    }
}
void dfs2(int u,int chain)
{
    id[u]=++sz;//分配x结点在线段树中的编号 dfs序
	top[u]=chain; //所在链
    rk[sz]=u;
    if(!son[u]){
        return;
    }
    dfs2(son[u],chain);
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v!=fa[u]&&v!=son[u]){
            dfs2(v,v);//其余儿子新开重链
        }  
    }
}
//空的线段树，因为要按dfs序建
void build(int i,int l,int r){
    tree[i].l=l;
    tree[i].r=r;
    if(l==r){
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
}
//懒惰标记用于区间更新
void pushdown(int i){
    tree[lson].sum+=(tree[lson].r-tree[lson].l+1)*tree[i].tag;
    tree[rson].sum+=(tree[rson].r-tree[rson].l+1)*tree[i].tag;
    tree[lson].tag+=tree[i].tag;
    tree[rson].tag+=tree[i].tag;
    tree[i].tag=0;
}
//单点更新
void change(int i,int x,int y){
    int l=tree[i].l,r=tree[i].r,mid=(l+r)>>1;
    if(l==r){
        tree[i].sum=tree[i].mx=y;
        return;
    }
    if(x<=mid){
        change(lson,x,y);
    }
    else{
        change(rson,x,y);
    }
    tree[i].sum=tree[lson].sum+tree[rson].sum;
    tree[i].mx=max(tree[lson].mx,tree[rson].mx);
}
//线段树区间求和
int querysum(int i,int x,int y){
    int l=tree[i].l,r=tree[i].r,mid=(l+r)>>1;
    if(x==l && r==y){
        return tree[i].sum;
    }
    if(y<=mid){
        return querysum(lson,x,y);
    }else if(x>mid){
        return querysum(rson,x,y);
    }else{
        return querysum(lson,x,mid)+querysum(rson,mid+1,y);
    }
}
//区间最大值
int querymax(int i,int x,int y){
    int l=tree[i].l,r=tree[i].r,mid=(l+r)>>1;
    if(x==l && r==y){
        return tree[i].mx;
    }
    if(y<=mid){
        return querymax(lson,x,y);
    }else if(x>mid){
        return querymax(rson,x,y);
    }else{
        return max(querymax(lson,x,mid),querymax(rson,mid+1,y));
    }
}
//x到y路径上节点权值和
int solvesum(int x,int y){
	int sum=0;
    //在不同的链上，id[top[x]],id[x]的查询保证如果是轻链就查询一个点，如果是种类就查询整个区间
    while(top[x]!=top[y]){
		//深度大的先上来
        if(dep[top[x]]<dep[top[y]]){
            swap(x,y);
        }     
		sum+=querysum(1,id[top[x]],id[x]);
        //不能两个同时上升，可能会“擦肩而过”
		x=fa[top[x]];
	}
    //top[x]==top[y]说明两个点在一条重链上了，如果这两个点是在一个点的不同叉上，top不可能相等
	//保持id[x]小
    if(id[x]>id[y]){
        swap(x,y);
    }
    //重链上转化为线段树的区间查询
	sum+=querysum(1,id[x],id[y]);
    return sum;
}
int solvemax(int x,int y)
{
	int mx=-INF;
    while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]){
            swap(x,y);
        }
		mx=max(mx,querymax(1,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if(id[x]>id[y]){
        swap(x,y);
    }
	mx=max(mx,querymax(1,id[x],id[y]));
    return mx;
}
int main()
{
    scanf("%d",&n);
    init();
    for(int i=1;i<n;i++)
    {
		int x,y;
		scanf("%d%d",&x,&y);
		addEdge(x,y);
	}
    for(int i=1;i<=n;i++)scanf("%d",&v[i]);
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    for(int i=1;i<=n;i++){
        change(1,id[i],v[i]);
    }
	scanf("%d",&q);
    while(q--){
        int x,y;scanf("%s%d%d",ch,&x,&y);
        if(ch[0]=='C'){
            v[x]=y;
            change(1,id[x],y);
        }
        else{
            if(ch[1]=='M'){
               printf("%d\n",solvemax(x,y));
            }
            else{
                printf("%d\n",solvesum(x,y));
            }
        }
    }
    return 0;
}